//
//  Extension.swift
//  SwiftStudy
//
//  Created by apple on 16/12/25.
//  Copyright © 2016年 com.zaoguankeji.www. All rights reserved.
//

import Foundation


///事实上，RandomAccessCollection 提供了我们想要的基本接口：可随机访问的集合保证了所需开销时间都是恒定的，而这些开销主要集中在测量索引间距离以及访问任意索引所指向的元素。
///因此，把 random 函数定义成 RandomAccessCollection 中的方法（这里用到 numericCasts 是因为不同集合类型的 IndexDistance 是不同的）：
extension RandomAccessCollection {
    
    func random() -> Iterator.Element? {
        guard count > 0 else {return nil}
        let offset = arc4random_uniform(numericCast(count))
        let i = index(startIndex, offsetBy:numericCast(offset))
        return self[i]
        
    }
    
    
}


//我发现 DispatchTime 使用起来没有想象中便利。在一款 GUI 的应用中，我总是想要指定一个 TimeInterval，也就是以秒为单位的整数或者分数形式。



///dispatchTime
extension DispatchTime: ExpressibleByIntegerLiteral {
    
    public init(integerLiteral value: Int) {
        self = DispatchTime.now() + .seconds(value)
    }
}


extension DispatchTime: ExpressibleByFloatLiteral {
    
    public init(floatLiteral value: Double) {
        self = DispatchTime.now() + .milliseconds(Int(value * 1000))
    }
    
    
}

///Then简单定义属性

public protocol Then {}

extension Then where Self: Any {
    /// Makes it available to set properties with closures just after initializing.
    ///
    ///     let label = UILabel().then {
    ///         $0.textAlignment = .Center
    ///         $0.textColor = UIColor.blackColor()
    ///         $0.text = "Hello, World!"
    ///     }
    public func then( block: (inout Self) -> Void) -> Self {
        var copy = self
        block(&copy)
        return copy
    }
}

extension Then where Self: AnyObject {
    /// Makes it available to set properties with closures just after initializing.
    ///
    ///     let label = UILabel().then {
    ///         $0.textAlignment = .Center
    ///         $0.textColor = UIColor.blackColor()
    ///         $0.text = "Hello, World!"
    ///     }
    public func then( block: (Self) -> Void) -> Self {
        block(self)
        return self
    }
}

extension NSObject: Then {}

///
///nillError
public struct NilError: Error, CustomStringConvertible {
    public var description: String { return _description }
    public init(file: String, line: Int) {
        _description = "Nil returned at "
            + (file as NSString).lastPathComponent + ":\(line)"
    }
    private let _description: String
}

extension Optional {
    public func unwrap(file: String = #file, line: Int = #line) throws -> Wrapped {
        guard let unwrapped = self else { throw NilError(file: file, line: line) }
        return unwrapped
    }
}

func associatedObject<ValueType: AnyObject>(
    _ base: AnyObject,
    key: UnsafePointer<UInt8>,
    initialiser: () -> ValueType)
    -> ValueType {
        if let associated = objc_getAssociatedObject(base, key)
            as? ValueType { return associated }
        let associated = initialiser()
        objc_setAssociatedObject(base, key, associated,
                                 .OBJC_ASSOCIATION_RETAIN)
        return associated
}

func associateObject<ValueType: AnyObject>(
    _ base: AnyObject,
    key: UnsafePointer<UInt8>,
    value: ValueType) {
    objc_setAssociatedObject(base, key, value,
                             .OBJC_ASSOCIATION_RETAIN)
}


